1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.hiprenderer.backend.d3d.d3drenderer; 12 version(Windows): 13 version(DirectX): 14 15 pragma(lib, "ole32"); 16 pragma(lib, "d3dcompiler"); 17 // pragma(lib, "d3dcompiler_47"); 18 pragma(lib, "d3d11"); 19 pragma(lib, "dxgi"); 20 21 import core.stdc.string; 22 import hip.util.string:fromStringz; 23 24 import directx.d3d11; 25 import directx.d3d11_3; 26 import directx.dxgi1_4; 27 28 29 import hip.util.system; 30 import hip.config.opts; 31 import hip.error.handler; 32 33 import hip.hiprenderer.shader; 34 import hip.hiprenderer.viewport; 35 import hip.hiprenderer.renderer; 36 import hip.hiprenderer.framebuffer; 37 38 import hip.hiprenderer.backend.d3d.d3dshader; 39 import hip.hiprenderer.backend.d3d.d3dframebuffer; 40 import hip.hiprenderer.backend.d3d.d3dvertex; 41 import hip.hiprenderer.backend.d3d.d3dtexture; 42 43 44 version(UWP) 45 { 46 import hip.bind.external : getCoreWindow, HipExternalCoreWindow; 47 } 48 else version = WindowsNative; 49 50 ID3D11Device3 _hip_d3d_device = null; 51 ID3D11DeviceContext _hip_d3d_context = null; 52 ID3D11DeviceContext3 _hip_d3d_context3 = null; 53 IDXGISwapChain3 _hip_d3d_swapChain = null; 54 ID3D11RenderTargetView _hip_d3d_mainRenderTarget = null; 55 private __gshared bool errorCheckEnabled = true; 56 57 58 void d3dCall(HRESULT delegate() dg, string file = __FILE__, size_t line = __LINE__) 59 { 60 auto res = dg(); 61 if(FAILED(res)) 62 { 63 // getWindowsErrorMessage(hr); 64 HipRenderer.exitOnError(file, line); 65 } 66 } 67 68 class Hip_D3D11_Renderer : IHipRendererImpl 69 { 70 import hip.windowing.window; 71 public static HipWindow window = null; 72 protected static bool hasDebugAvailable; 73 package static D3D11_BLEND_DESC blend; 74 protected static ID3D11BlendState blendState; 75 protected static Viewport currentViewport; 76 public static Shader currentShader; 77 78 static if(HIP_DEBUG) 79 { 80 import directx.dxgidebug; 81 IDXGIInfoQueue dxgiQueue; 82 } 83 84 85 static void assertExit(HRESULT hres, string msg, 86 string file = __FILE__, size_t line = __LINE__, 87 string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 88 { 89 ErrorHandler.assertLazyExit(SUCCEEDED(hres), msg~":\n\t"~getWindowsErrorMessage(hres),file,line,mod,func); 90 } 91 92 protected void createD3DDevice() 93 { 94 uint createDeviceFlags = 0; 95 static if(HIP_DEBUG){ 96 pragma(msg, "D3D11_CREATE_DEVICE_DEBUG:\n\tComment this flag if you do not have d3d11 debug device installed"); 97 /** 98 * https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-layers#debug-layer 99 * 100 * For Windows 10, to create a device that supports the debug layer, 101 * enable the "Graphics Tools" optional feature. Go to the Settings panel, 102 * under System, Apps & features, Manage optional Features, 103 * Add a feature, and then look for "Graphics Tools". 104 */ 105 createDeviceFlags|= D3D11_CREATE_DEVICE_DEBUG; 106 } 107 const D3D_FEATURE_LEVEL[] levelArray = 108 [ 109 D3D_FEATURE_LEVEL_12_1, 110 D3D_FEATURE_LEVEL_12_0, 111 D3D_FEATURE_LEVEL_11_1, 112 D3D_FEATURE_LEVEL_11_0, 113 D3D_FEATURE_LEVEL_10_1, 114 D3D_FEATURE_LEVEL_10_0, 115 D3D_FEATURE_LEVEL_9_3, 116 D3D_FEATURE_LEVEL_9_1 117 ]; 118 D3D_FEATURE_LEVEL featureLevel; 119 120 ID3D11Device device; 121 ID3D11DeviceContext context; 122 HRESULT hres = D3D11CreateDevice(cast(IDXGIAdapter)null, 123 D3D_DRIVER_TYPE_HARDWARE, 124 null, createDeviceFlags, 125 levelArray.ptr, 126 cast(uint)levelArray.length, 127 D3D11_SDK_VERSION, 128 &device, 129 &featureLevel, 130 &context 131 ); 132 133 if (FAILED(hres)) 134 { 135 ErrorHandler.showWarningMessage("D3D11: Hardware rendering device creation failed", 136 "HipRenderer will try to use software renderer"); 137 // Initialization failed, fall back to the WARP device. 138 hres = D3D11CreateDevice( 139 cast(IDXGIAdapter)null, 140 D3D_DRIVER_TYPE_WARP, 141 null, 142 createDeviceFlags, 143 levelArray.ptr, 144 cast(uint)levelArray.length, 145 D3D11_SDK_VERSION, 146 &device, 147 &featureLevel, 148 &context); 149 assertExit(SUCCEEDED(hres), "D3D11 Could not creating any rendering context: "); 150 } 151 152 device.QueryInterface(&IID_ID3D11Device3, cast(void**)&_hip_d3d_device); 153 _hip_d3d_context = context; 154 } 155 156 version(UWP) 157 protected void createD3DSwapChainForCoreWindow(HipExternalCoreWindow wnd, HipRendererConfig* config) 158 { 159 DXGI_SWAP_CHAIN_DESC1 dsc; 160 import core.stdc.string; 161 memset(&dsc, 0, DXGI_SWAP_CHAIN_DESC1.sizeof); 162 dsc.Width = wnd.logicalWidth; 163 dsc.Height = wnd.logicalHeight; 164 dsc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 165 dsc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 166 dsc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 167 168 ubyte bufferCount = 2; 169 ubyte samplingLevel = 1; 170 if(config != null) 171 bufferCount = config.bufferingCount; 172 if(config != null && config.multisamplingLevel > 0) 173 samplingLevel = config.multisamplingLevel; 174 175 dsc.BufferCount = bufferCount; 176 dsc.SampleDesc.Count = samplingLevel; 177 dsc.SampleDesc.Quality = 0; 178 // dsc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 179 dsc.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH; 180 dsc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; 181 182 183 IDXGIDevice3 dxgiDevice; 184 assertExit( 185 _hip_d3d_device.QueryInterface(&IID_IDXGIDevice3, cast(void**)&dxgiDevice) 186 ,"Could not get the IDXGIDevice3 interface"); 187 188 IDXGIAdapter adapter; 189 assertExit( 190 dxgiDevice.GetAdapter(&adapter) 191 , "Could not get DXGI Adapter"); 192 193 IDXGIFactory4 factory; 194 assertExit( 195 adapter.GetParent(&IID_IDXGIFactory4, cast(void**)&factory) 196 ,"Could not get IDXGIFactory4"); 197 198 IDXGISwapChain1 swapChain; 199 assertExit(factory.CreateSwapChainForCoreWindow ( 200 cast(IUnknown)_hip_d3d_device, 201 cast(IUnknown)wnd.coreWindow, 202 &dsc, 203 cast(IDXGIOutput)null, 204 &swapChain 205 ), "Could not create swap chain for CoreWindow"); 206 207 swapChain.QueryInterface(&IID_IDXGISwapChain3, cast(void**)&_hip_d3d_swapChain); 208 } 209 210 protected void initD3DDebug() 211 { 212 static if(HIP_DEBUG) 213 { 214 import hip.util.windows; 215 HRESULT hres; 216 DXGIGetDebugInterface = cast(_DXGIGetDebugInterface)GetProcAddress(GetModuleHandle("Dxgidebug.dll"), "DXGIGetDebugInterface"); 217 if(DXGIGetDebugInterface is null) 218 { 219 ErrorHandler.showErrorMessage("DLL Error", "Error loading the DXGIGetDebugInterface from Dxgidebug.dll 220 Debug layer will be aborted."); 221 return; 222 } 223 hres = DXGIGetDebugInterface(&uuidof!IDXGIInfoQueue, cast(void**)&dxgiQueue); 224 if(FAILED(hres)) 225 { 226 ErrorHandler.showErrorMessage("DXGI Error", "Could not get the IDXGIInfoQueue interface. \nError: " ~ 227 getWindowsErrorMessage(hres) ~ "\nDebug layer will be aborted."); 228 } 229 else 230 hasDebugAvailable = true; 231 } 232 } 233 234 protected void initD3DRenderTargetView() 235 { 236 HRESULT res; 237 ID3D11Texture2D pBackBuffer; 238 239 res = _hip_d3d_swapChain.GetBuffer(0, &IID_ID3D11Texture2D, cast(void**)&pBackBuffer); 240 ErrorHandler.assertLazyErrorMessage(SUCCEEDED(res), "Error creating D3D11Texture2D", getWindowsErrorMessage(res)); 241 242 //Use back buffer address to create a render target 243 res = _hip_d3d_device.CreateRenderTargetView(pBackBuffer, null, &_hip_d3d_mainRenderTarget); 244 ErrorHandler.assertLazyErrorMessage(SUCCEEDED(res), "Error creating render target view", getWindowsErrorMessage(res)); 245 pBackBuffer.Release(); 246 247 _hip_d3d_context.OMSetRenderTargets(1u, &_hip_d3d_mainRenderTarget, null); 248 setState(); 249 } 250 protected void initD3DFowHWND(HWND hwnd, HipRendererConfig* config) 251 { 252 DXGI_SWAP_CHAIN_DESC dsc; 253 dsc.OutputWindow = hwnd; 254 dsc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 255 dsc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 256 dsc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 257 258 ubyte bufferCount = 2; 259 ubyte samplingLevel = 1; 260 if(config != null) 261 bufferCount = config.bufferingCount; 262 if(config != null && config.multisamplingLevel > 0) 263 samplingLevel = config.multisamplingLevel; 264 265 dsc.BufferCount = bufferCount; 266 dsc.SampleDesc.Count = samplingLevel; 267 dsc.SampleDesc.Quality = 0; 268 dsc.Windowed = TRUE; //True 269 //Let user being able to switch between fullscreen and windowed 270 dsc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 271 272 // dsc.BufferDesc.RefreshRate.Numerator = 60; 273 // dsc.BufferDesc.RefreshRate.Denominator = 1; 274 275 uint createDeviceFlags = 0; 276 static if(HIP_DEBUG) 277 createDeviceFlags|= D3D11_CREATE_DEVICE_DEBUG; 278 const D3D_FEATURE_LEVEL[] levelArray = 279 [ 280 D3D_FEATURE_LEVEL_11_1, 281 D3D_FEATURE_LEVEL_11_0, 282 D3D_FEATURE_LEVEL_10_1, 283 D3D_FEATURE_LEVEL_10_0, 284 D3D_FEATURE_LEVEL_9_3, 285 D3D_FEATURE_LEVEL_9_1 286 ]; 287 D3D_FEATURE_LEVEL featureLevel; 288 289 ID3D11Device device; 290 IDXGISwapChain swapChain; 291 auto res = D3D11CreateDeviceAndSwapChain(null, 292 D3D_DRIVER_TYPE_HARDWARE, 293 null, 294 createDeviceFlags, 295 levelArray.ptr, 296 cast(uint)levelArray.length, 297 D3D11_SDK_VERSION, 298 &dsc, 299 &swapChain, 300 &device, 301 &featureLevel, 302 &_hip_d3d_context); 303 304 305 306 swapChain.QueryInterface(&IID_IDXGISwapChain3, cast(void**)&_hip_d3d_swapChain); 307 device.QueryInterface(&IID_ID3D11Device3, cast(void**)&_hip_d3d_device); 308 309 310 if(ErrorHandler.assertLazyErrorMessage(SUCCEEDED(res), "D3D11: Error creating device and swap chain", getWindowsErrorMessage(res))) 311 { 312 Hip_D3D11_Dispose(); 313 return; 314 } 315 316 initD3DDebug(); 317 initD3DRenderTargetView(); 318 } 319 320 version(UWP) 321 protected void initD3DForCoreWindow(HipExternalCoreWindow wnd, HipRendererConfig* config) 322 { 323 createD3DDevice(); 324 initD3DDebug(); 325 createD3DSwapChainForCoreWindow(wnd, config); 326 initD3DRenderTargetView(); 327 } 328 329 /** 330 * Create a rasterizer state 331 */ 332 public void setState() 333 { 334 D3D11_RASTERIZER_DESC desc; 335 desc.CullMode = D3D11_CULL_NONE; 336 ID3D11RasterizerState state; 337 338 if(FAILED(_hip_d3d_device.CreateRasterizerState(&desc, &state))) 339 HipRenderer.exitOnError(); 340 341 _hip_d3d_context.RSSetState(state); 342 } 343 public final bool isRowMajor(){return false;} 344 void setErrorCheckingEnabled(bool enable = true) 345 { 346 errorCheckEnabled = enable; 347 } 348 349 public bool hasErrorOccurred(out string err, string file = __FILE__, size_t line = __LINE__) 350 { 351 if(hasDebugAvailable) 352 { 353 DXGI_INFO_QUEUE_MESSAGE* msg; 354 bool hasError; 355 size_t msgSize; 356 for(ulong i = 0, 357 // len = dxgiQueue.GetNumStoredMessagesAllowedByRetrievalFilters(DXGI_DEBUG_DX); 358 len = dxgiQueue.GetNumStoredMessages(DXGI_DEBUG_DX); 359 i < len; i++) 360 { 361 import core.stdc.stdlib; 362 dxgiQueue.GetMessage(DXGI_DEBUG_DX, i, null, &msgSize); 363 msg = cast(DXGI_INFO_QUEUE_MESSAGE*)malloc(msgSize); 364 dxgiQueue.GetMessage(DXGI_DEBUG_DX, i, msg, &msgSize); 365 if(msg.pDescription !is null || msg.Severity == DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR) 366 { 367 hasError = true; 368 err~= msg.pDescription.fromStringz~"\n"; 369 } 370 free(msg); 371 } 372 return hasError; 373 } 374 else 375 { 376 HRESULT hres = GetLastError(); 377 err = getWindowsErrorMessage(hres); 378 return FAILED(hres); 379 } 380 } 381 382 public bool setWindowMode(HipWindowMode mode) 383 { 384 final switch(mode) with(HipWindowMode) 385 { 386 case BORDERLESS_FULLSCREEN: 387 break; 388 case FULLSCREEN: 389 break; 390 case WINDOWED: 391 392 break; 393 } 394 return false; 395 } 396 397 public IHipFrameBuffer createFrameBuffer(int width, int height) 398 { 399 return new Hip_D3D11_FrameBuffer(width,height); 400 } 401 public IHipVertexArrayImpl createVertexArray() 402 { 403 return new Hip_D3D11_VertexArrayObject(); 404 } 405 public IHipTexture createTexture() 406 { 407 return new Hip_D3D11_Texture(); 408 } 409 public IHipVertexBufferImpl createVertexBuffer(size_t size, HipBufferUsage usage) 410 { 411 return new Hip_D3D11_VertexBufferObject(size, usage); 412 } 413 public IHipIndexBufferImpl createIndexBuffer(index_t count, HipBufferUsage usage) 414 { 415 return new Hip_D3D11_IndexBufferObject(count, usage); 416 } 417 418 public Shader createShader() 419 { 420 return new Shader(new Hip_D3D11_ShaderImpl()); 421 } 422 423 bool isBlendingEnabled() const 424 { 425 version(none)ErrorHandler.assertExit(false, "Unimplemented"); 426 return false; 427 } 428 429 public bool init(HipWindow window) 430 { 431 version(UWP){assert(false, "Cannot call 'init' on UWP. Use initExternal");} 432 else 433 { 434 this.window = window; 435 436 HipRendererConfig cfg = HipRenderer.getCurrentConfig(); 437 initD3DFowHWND(window.hwnd, &cfg); 438 HipRenderer.rendererType = HipRendererType.D3D11; 439 440 return ErrorHandler.stopListeningForErrors(); 441 } 442 } 443 444 version(dll) 445 { 446 public bool initExternal() 447 { 448 HipRendererConfig cfg; 449 initD3DForCoreWindow(getCoreWindow(), &cfg); 450 return true; 451 } 452 } 453 454 public int queryMaxSupportedPixelShaderTextures() 455 { 456 return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; 457 } 458 459 private int getRendererMode(HipRendererMode mode) 460 { 461 final switch(mode) with (HipRendererMode) 462 { 463 case TRIANGLES: 464 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; 465 case TRIANGLE_STRIP: 466 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; 467 case LINE: 468 return D3D11_PRIMITIVE_TOPOLOGY_LINELIST; 469 case LINE_STRIP: 470 return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; 471 case POINT: 472 return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; 473 } 474 } 475 476 public void setRendererMode(HipRendererMode mode) 477 { 478 _hip_d3d_context.IASetPrimitiveTopology(getRendererMode(mode)); 479 } 480 481 public void setViewport(Viewport v) 482 { 483 import hip.windowing.platforms.windows; 484 version(WindowsNative) 485 int[2] borders = getWindowBorder(window.hwnd); 486 else 487 int[2] borders = [0,0]; 488 489 D3D11_VIEWPORT vp; 490 memset(&vp, 0, D3D11_VIEWPORT.sizeof); 491 vp.Width = v.width - borders[0]; 492 vp.Height = v.height - borders[1]; 493 vp.TopLeftX = v.x; 494 vp.TopLeftY = v.y; 495 // vp.MinDepth = 0; 496 // vp.MaxDepth = 1; 497 498 499 currentViewport = v; 500 _hip_d3d_context.RSSetViewports(1u, &vp); 501 } 502 503 504 505 void setColor(ubyte r = 255, ubyte g = 255, ubyte b = 255, ubyte a = 255){} 506 void setShader(Shader s) 507 { 508 currentShader = s; 509 } 510 511 void begin() 512 { 513 // if(HipRenderer.currentShader != currentShader) 514 // HipRenderer.setShader(currentShader); 515 _hip_d3d_context.OMSetRenderTargets(1u, &_hip_d3d_mainRenderTarget, null); 516 } 517 void end() 518 { 519 _hip_d3d_swapChain.Present(0,0); 520 } 521 522 public void drawVertices(index_t count, uint offset = 0) 523 { 524 _hip_d3d_context.Draw(count, offset); 525 } 526 public void drawIndexed(index_t indicesSize, uint offset=0) 527 { 528 _hip_d3d_context.DrawIndexed(indicesSize, offset, 0); 529 } 530 void clear(){} 531 532 void clear(ubyte r = 255, ubyte g = 255, ubyte b = 255, ubyte a = 255) 533 { 534 float[4] color = [cast(float)r/255, cast(float)g/255, cast(float)b/255, cast(float)a/255]; 535 _hip_d3d_context.ClearRenderTargetView(_hip_d3d_mainRenderTarget, color.ptr); 536 } 537 538 public void dispose() 539 { 540 Hip_D3D11_Dispose(); 541 } 542 543 public void setDepthTestingFunction(HipDepthTestingFunction) 544 { 545 546 } 547 public void setDepthTestingEnabled(bool) 548 { 549 550 } 551 public void setStencilTestingEnabled(bool bEnable) 552 { 553 } 554 555 public void setStencilTestingMask(uint mask) 556 { 557 } 558 559 public void setColorMask(ubyte r, ubyte g, ubyte b, ubyte a) 560 { 561 562 } 563 564 public void setStencilTestingFunction(HipStencilTestingFunction passFunc, uint reference, uint mask) 565 { 566 } 567 568 public void setStencilOperation(HipStencilOperation stencilFail, HipStencilOperation depthFail, HipStencilOperation stencilAndDephPass) 569 { 570 } 571 572 public ShaderVar* createShaderVar(ShaderTypes shaderType, UniformType uniformType, string varName, size_t length) 573 { 574 return null; 575 } 576 577 578 } 579 580 private void Hip_D3D11_Dispose() 581 { 582 if(_hip_d3d_swapChain) 583 { 584 _hip_d3d_swapChain.SetFullscreenState(FALSE, null); 585 _hip_d3d_swapChain.Release(); 586 _hip_d3d_swapChain = null; 587 } 588 if(_hip_d3d_context) 589 { 590 _hip_d3d_context.Release(); 591 _hip_d3d_context = null; 592 } 593 if(_hip_d3d_device) 594 { 595 _hip_d3d_device.Release(); 596 _hip_d3d_device = null; 597 } 598 if(_hip_d3d_mainRenderTarget) 599 { 600 _hip_d3d_mainRenderTarget.Release(); 601 _hip_d3d_mainRenderTarget = null; 602 } 603 } 604